﻿using MockCommon;
using MockDataAccess;
using MockDataTransferObject;
using System;
using System.Data;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace MockBusiness
{
    /// <summary>
    /// Client business
    /// </summary>
    public class ClientBusiness
    {
        #region Initialize
        private static ClientBusiness _instance;
        private readonly ClientDataAccess _clientDataAccess;
        private readonly RoleDataAccess _roleDataAccess;
        private readonly UserDataAccess _userDataAccess;

        /// <summary>
        /// Gets the client data test.
        /// </summary>
        public Collection<Client> ClientDataTest
        {
            get
            {
                return _clientDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the role data test.
        /// </summary>
        public Collection<Role> RoleDataTest
        {
            get
            {
                return _roleDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the user data test.
        /// </summary>
        public Collection<User> UserDataTest
        {
            get
            {
                return _userDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="ClientBusiness"/> class from being created.
        /// </summary>
        private ClientBusiness()
        {
            _clientDataAccess = new ClientDataAccess();
            _roleDataAccess = new RoleDataAccess();
            _userDataAccess = new UserDataAccess();
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="ClientBusiness"/> class from being created.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        private ClientBusiness(bool isFake)
        {
            _clientDataAccess = new ClientDataAccess(isFake);
            _roleDataAccess = new RoleDataAccess(isFake);
            _userDataAccess = new UserDataAccess(isFake);
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <returns></returns>
        public static ClientBusiness RetrieveInstance()
        {
            if (_instance == null)
                _instance = new ClientBusiness();
            return _instance;
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        /// <returns></returns>
        public static ClientBusiness RetrieveInstance(bool isFake)
        {
            if (_instance == null)
                _instance = new ClientBusiness(isFake);
            return _instance;
        }
        #endregion

        #region CUD
        /// <summary>
        /// Inserts the specified client.
        /// </summary>
        /// <param name="client">The client.</param>
        public void Insert(Client client)
        {
            if (client == null)
            {
                throw new MockException("Client is null", "Business");
            }
            if (_clientDataAccess.Exist(client.ClientId))
            {
                throw new MockException("ClientId was existed", "Business");
            }
            User user = client.User;
            if (user == null)
            {
                throw new MockException("User is null", "Business");
            }
            if (_userDataAccess.Exist(user.UserId))
            {
                throw new MockException("User was existed", "Business");
            }
            Role role = client.User.Role;
            if (role == null)
            {
                throw new MockException("Role is null", "Business");
            }
            if (!_roleDataAccess.Exist(role.RoleId))
            {
                throw new MockException("Role was not existed", "Business");
            }
            
            if (_userDataAccess.IsExistUserName(user.UserName))
            {
                throw new MockException("Username was existed", "Business");
            }
            if (String.IsNullOrEmpty(client.FirstName))
            {
                throw new MockException("Firstname is required", "Business");
            }
            string lastName = client.LastName;
            lastName = lastName.Trim();
            if (String.IsNullOrEmpty(client.LastName) || lastName.IndexOf(" ", StringComparison.CurrentCulture) != -1)
            {
                throw new MockException("Lastname must be a word", "Business");
            }
            _clientDataAccess.Create(client, true);
        }

        /// <summary>
        /// Updates the specified client.
        /// </summary>
        /// <param name="client">The client.</param>
        public void Update(Client client)
        {
            if (client == null)
            {
                throw new MockException("Client is null", "Business");
            }
            if (!_clientDataAccess.Exist(client.ClientId))
            {
                throw new MockException("ClientId was not existed", "Business");
            }
            if (client.User == null)
            {
                throw new MockException("User is null", "Business");
            }
            Role role = client.User.Role;
            if (role == null)
            {
                throw new MockException("Role is null", "Business");
            }
            if (!_roleDataAccess.Exist(role.RoleId))
            {
                throw new MockException("Role was not existed", "Business");
            }
            if (String.IsNullOrEmpty(client.FirstName))
            {
                throw new MockException("Firstname is required", "Business");
            }
            string lastName = client.LastName;
            lastName = lastName.Trim();
            if (String.IsNullOrEmpty(client.LastName) || lastName.IndexOf(" ", StringComparison.CurrentCulture) != -1)
            {
                throw new MockException("Lastname must be a word", "Business");
            }
            _clientDataAccess.Update(client, true);
        }

        /// <summary>
        /// Deletes the specified client id.
        /// </summary>
        /// <param name="clientId">The client id.</param>
        public void Delete(string clientId)
        {
            if (clientId == null)
            {
                throw new MockException("ClientId is null", "Business");
            }
            if (!_clientDataAccess.Exist(clientId))
            {
                throw new MockException("ClientId is not exist", "Business");
            }
            int count = GetCountManagementContract(clientId);
            if (count > 0)
            {
                throw new MockException("Delete failed because this client was managing "+ count + " contract(s)", "Business");
            }           
            _clientDataAccess.Delete(clientId);
        }
        #endregion

        #region R
        /// <summary>
        /// Retrieves all clients.
        /// </summary>
        /// <returns></returns>
        public Collection<Client> RetrieveAllClients()
        {
            return _clientDataAccess.RetrieveAllClients();
        }

        /// <summary>
        /// Retrieves all client users.
        /// </summary>
        /// <returns></returns>
        public DataTable RetrieveAllClientUsers()
        {
            return _clientDataAccess.RetrieveAllClientUsers();
        }

        /// <summary>
        /// Gets the name of the client id by user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public object GetClientIdByUserName(string userName)
        {
            if (userName == null)
                return null;
            return _clientDataAccess.GetClientIdByClientUserName(userName);
        }

        /// <summary>
        /// Gets the name of the by user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public Client GetByUserName(string userName)
        {
            if (userName == null)
                return null;
            return _clientDataAccess.GetByUserName(userName);
        }

        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="clientId">The client id.</param>
        /// <returns></returns>
        public Client GetById(object clientId)
        {
            return _clientDataAccess.GetById(clientId);
        }

        /// <summary>
        /// Gets the client user name by contract id.
        /// </summary>
        /// <param name="contractId">The contract id.</param>
        /// <returns></returns>
        public string GetClientUserNameByContractId(Guid contractId)
        {
            return _clientDataAccess.GetClientUserNameByContractId(contractId);
        }

        /// <summary>
        /// Gets the count management contract.
        /// </summary>
        /// <param name="clientId">The client id.</param>
        /// <returns></returns>
        public int GetCountManagementContract(string clientId)
        {
            if (clientId == null)
            {
                throw new MockException("ClientId is null", "Business");
            }
            if (!_clientDataAccess.Exist(clientId))
            {
                throw new MockException("ClientId was not existed", "Business");
            }
            return (int)_clientDataAccess.GetCountManagementContract(clientId);
        }

        /// <summary>
        /// Gets the clients by filter.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="email">The email.</param>
        /// <param name="firstName">The first name.</param>
        /// <param name="lastName">The last name.</param>
        /// <param name="isActive">The is active.</param>
        /// <returns></returns>
        public Collection<Client> GetClientsByFilter(object userName, object email, object firstName, object lastName, object isActive)
        {
            return _clientDataAccess.GetByFilter(userName, email, firstName, lastName, isActive);
        } 
        #endregion R
    }
}
